// tga.cc -- handles reading tga files

/*
   Copyright 2006 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include <tga.h>

typedef struct {	// TGA file header
	uint8 id_length;
	uint8 colormap_type;
	uint8 image_type;
	uint16 colormap_index;
	uint16 colormap_length;
	uint8 colormap_size;
	uint16 x_origin;
	uint16 y_origin;
	uint16 width;
	uint16 height;
	uint8 pixel_size;
	uint8 attributes;
} __attribute__ ((packed)) TGAHeader;

void tga_decode(uint8 *tga, texinfo *tex) {
	int columns, rows, numPixels;
	int row, column;

	//_DEBUG("!!! Header size %d\n", sizeof(TGAHeader));

	uint8 *rgba, *dest;
	TGAHeader *header;

	uint8 red=0, green=0, blue=0, alpha=0, packetHeader, packetSize, j;
//	uint8 *tga = file;

	header = (TGAHeader *) tga;
	tga += sizeof(TGAHeader);


	// Only types 2 and 10 are supported
	if (header->image_type != 2 && header->image_type != 10) {
		tex->mem = 0;
		
		//_DEBUG("!!! Unsupported image type %d\n", header->image_type);
		return;
	}

	// Only 24bit or 32bit pixels are supported
	if (header->colormap_type != 0 ||
		(header->pixel_size != 32 && header->pixel_size != 24)) {
		tex->mem = 0;
		
		//_DEBUG("!!! Unsupported pixel size %d\n", header->pixel_size);
		return;
	}

	columns = header->width;
	rows = header->height;
	numPixels = columns * rows;
	header->pixel_size == 32 ? tex->bpp = 4 : tex->bpp = 3;

	tex->width = columns;
	tex->height = rows;
	
	// no ID yet
	tex->num = ~0;

	// Allocate memory for decoded image
	rgba = new uint8[numPixels*(tex->bpp)];
	
	if (!rgba) {
		tex->mem = 0;
		
		//_DEBUG("!!! Failed to allocate %d bytes\n", numPixels*tex->bpp);
		return;
	}

	
	// Uncompressed RGB image
	if (header->image_type == 2) {
		for(row = rows-1; row >= 0; row--) {
			dest = rgba + row*columns*(tex->bpp);
			
			for(column=0; column < columns; column++) {
				if (header->pixel_size == 24) {
					*dest++ = *tga++;
					*dest++ = *tga++;
					*dest++ = *tga++;
					
					/*
					blue = *tga; tga++;
					green = *tga; tga++;
					red = *tga; tga++;
					*dest++ = red;
					*dest++ = green;
					*dest++ = blue;
					*/
					//*dest++ = 255;
				} else if (header->pixel_size == 32) {
					*dest++ = *tga++;
					*dest++ = *tga++;
					*dest++ = *tga++;
					*dest++ = *tga++;
					
					/*
					blue = *tga; tga++;
					green = *tga; tga++;
					red = *tga; tga++;
					alpha = *tga; tga++;
					*dest++ = red;
					*dest++ = green;
					*dest++ = blue;
					*dest++ = alpha;
					*/
				}
			}
		}
	}
// RLE RGB image
	else if (header->image_type == 10) {
		for(row=rows-1; row>=0; row--) {
			dest = rgba + row*columns*(tex->bpp);

			for(column=0; column < columns; ) {
				packetHeader = *tga; tga++;
				packetSize = 1 + (packetHeader & 0x7f);
			// RLE packet
				if (packetHeader & 0x80) {
					if (header->pixel_size == 24) {
						blue = *tga; tga++;
						green = *tga; tga++;
						red = *tga; tga++;
						//alpha = 255;
					} else if (header->pixel_size==32) {
						blue = *tga; tga++;
						green = *tga; tga++;
						red = *tga; tga++;
						alpha = *tga; tga++;
					}
	
					for(j=0;j<packetSize;j++) {
						*dest++=blue;
						*dest++=green;
						*dest++=red;
						
						/*
						*dest++=red;
						*dest++=green;
						*dest++=blue;
						*/
						if(header->pixel_size==32) *dest++=alpha;
						column++;
						if (column==columns) {
							column=0;
							if (row>0)
								row--;
							else
								goto end_decode;
							dest = rgba + row*columns*(tex->bpp);
						}
					}
				}
			// Non-RLE packet
				else {
					for(j=0;j<packetSize;j++) {
						if (header->pixel_size==24) {
							*dest++ = *tga++;
							*dest++ = *tga++;
							*dest++ = *tga++;
							
							/*
							blue = *tga; tga++;
							green = *tga; tga++;
							red = *tga; tga++;
							*dest++ = red;
							*dest++ = green;
							*dest++ = blue;
							*/
							//*dest++ = 255;
						}
						else {
							*dest++ = *tga++;
							*dest++ = *tga++;
							*dest++ = *tga++;
							*dest++ = *tga++;
							
							/*
							blue = *tga; tga++;
							green = *tga; tga++;
							red = *tga; tga++;
							alpha = *tga; tga++;
							*dest++ = red;
							*dest++ = green;
							*dest++ = blue;
							*dest++ = alpha;
							*/
						}
						column++;
						if (column==columns) {
							column=0;
							if (row>0)
								row--;
							else
								goto end_decode;
							dest = rgba + row*columns*(tex->bpp);
						}						
					}
				}
			}
			end_decode:;
		}
	}	
	
	tex->mem=rgba;
	return;
}
